﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.IO;

namespace Common
{
    /// <summary>
    /// 插件管理器
    /// </summary>
    public class PluginManager
    {
        private string _pluginPath = string.Empty;// 插件目录
        private string _pluginSearchPattern = string.Empty;// 插件dll，匹配的搜索字符串
        private List<Assembly> _pluginAssembly;

        /// <summary>
        /// 插件构造.
        /// </summary>
        /// <param name="pluginPath">要搜索的插件目录.</param>
        /// <param name="pluginSearchPattern">要与 path 中的文件名匹配的搜索字符串。.</param>
        public PluginManager(string pluginPath, string pluginSearchPattern)
        {
            _pluginPath = pluginPath;
            _pluginSearchPattern = pluginSearchPattern;
        }

        /// <summary>
        /// 获取插件实例列表.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public List<T> GetPlugin<T>() where T : class
        {
            List<T> pluginList = new List<T>();
            foreach (Type type in GetPluginType<T>())
            {
                try
                {
                    T tmpT = Activator.CreateInstance(type, true) as T;
                    if (tmpT != null)
                    {
                        pluginList.Add(tmpT);
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error("加载配置插件出错：" + type.FullName+ex);
                }
            }
            return pluginList;
        }
        /// <summary>
        /// 获取插件Type列表.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public List<Type> GetPluginType<T>()
        {
            List<Type> pluginType = new List<Type>();//DEVECG-111 解决无法获取同一目录中的不同接口实现的问题
            foreach (Assembly assembly in GetPluginAssembly())
            {
                try
                {
                    foreach (Type type in assembly.GetTypes())
                    {
                        if (type.IsClass
                            && type.IsPublic
                            && !type.IsAbstract)//不创建抽象类
                        {
                            Type tmpType = type.GetInterface(typeof(T).FullName);
                            if (tmpType != null)
                            {
                                pluginType.Add(type);
                            }
                            else if (type.BaseType == typeof(T)//DEVECG-111 修复cs文件在项目文件夹中，导致GetInterface无法正常获取接口实现的问题。
                                || type.IsSubclassOf(typeof(T)))//兼容指定类型的子类
                            {
                                pluginType.Add(type);
                            }
                        }
                    }
                }
                catch (ReflectionTypeLoadException ex)
                {
                    LogHelper.Error("加载配置插件出错：" + assembly.FullName+ex);
                }
                catch (Exception ex)
                {
                    LogHelper.Error("加载配置插件出错：" + assembly.FullName+ex);
                }
            }
            return pluginType;
        }
        /// <summary>
        /// 获取插件程序集.
        /// </summary>
        /// <returns></returns>
        private List<Assembly> GetPluginAssembly()
        {
            if (_pluginAssembly == null)
            {
                if (!Path.IsPathRooted(_pluginPath))
                {
                    _pluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, _pluginPath);
                }
                if (!Directory.Exists(_pluginPath))
                {
                    Directory.CreateDirectory(_pluginPath);
                }
                _pluginAssembly = new List<Assembly>();
                foreach (string file in Directory.GetFiles(_pluginPath, _pluginSearchPattern))
                {
                    _pluginAssembly.Add(Assembly.LoadFrom(file));
                }
            }
            return _pluginAssembly;
        }

        //private static readonly object lockObj = new object();

        //private List<ISSO> _iSSOList;

        //private static ISSOProvider _instance;

        //public static ISSOProvider Instance
        //{
        //    get
        //    {
        //        if (_instance == null)
        //        {
        //            lock (lockObj)
        //            {
        //                if (_instance == null)
        //                {
        //                    _instance = new ISSOProvider();
        //                }
        //            }
        //        }

        //        return _instance;
        //    }
        //}

        //private ISSOProvider()
        //{
        //    PluginManager manager = new PluginManager(Path.Combine(NL.Common.Config.Local.GetAssemblyPath(), "SSO"),
        //        "SSO.*.dll");

        //    _iSSOList = manager.GetPlugin<ISSO>();
        //}
    }
}
